#include "stdint.h"
#include <memory>
#include <set>
#include <string>
#include "SerialPort.h"


namespace MC500
{

const uint8_t LCD_X_SIZE = 192;
const uint8_t LCD_Y_SIZE = 64;
const uint8_t LCD_RENDER_Y_SZIE = LCD_Y_SIZE / 8;

class DisplayDriver
{
public:
    DisplayDriver(std::shared_ptr<SerialPort> bus) : dirtyBlock(), lcdBuff_{0}, bus(bus){};
    ~DisplayDriver() = default;

    void WriteString(uint8_t x, uint8_t y, const std::string& str);

    void WriteChar(uint8_t x, uint8_t y, char c);

    /**
 * 写Img到缓存
 * 参数说明：
 * x：写入起始x偏移
 * y: 写入起始y偏移
 * img：数据数组。每个byte位同一个X位置垂直8bit的二进制数据，数据排列有限x轴排列。多余数据将被忽略。 如 数据顺序 { (x,y) , (x+1,y) , ..., (x, y+8),(x+1,y+8),... }
 * sizeX: img的宽度
 * sizeY: img的宽度。如果sizeY不能被8整除，请保证len(img) = (sizeY/8+1)*sizeX。
 */
    void WriteImg(const uint8_t x, const uint8_t y, const uint8_t *img, const uint8_t sizeX, const uint8_t sizeY);

    //缓存刷入屏幕
    //lazy: 只刷新修改过的部分
    void Refresh(bool lazy = true);

    void print();

private:
    bool SyncWithLCD();
    bool SendCMDToLCD(const uint8_t CMDID, const uint8_t Para);
    bool SelectLine(const uint8_t line);

    bool SetX(const uint8_t x);

    bool SendDataToLCD(uint8_t *data, uint8_t len);

    void WriteLCDLineByCombine(const uint8_t x, const uint8_t lineNo, const uint8_t *highNImg, const uint8_t *lowImg, const uint8_t highWriteBits);

    std::set<std::pair<uint8_t, uint8_t>> dirtyBlock;
    //存储格式，高位在上，低位在下。
    uint8_t lcdBuff_[LCD_Y_SIZE / 8][LCD_X_SIZE];
    // ASCII码 '!' 到 '~'所有可见字符
    const static uint8_t ASCIIChars[95][16];

    std::shared_ptr<SerialPort> bus;
};

}; // namespace MC500
